﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel;

namespace MockupDesigner.AppItems.Commands
{
    public class BackwardForwardCommand : ICommand
    {

        public CommandType CommandType
        {
            get { return CommandType.Undoable; }
        }

        private DesignerCanvas designerCanvas;
        private MovementType movementType;

        private List<UIElement> ordered = new List<UIElement>();
        private Dictionary<UIElement, int> elementsChanged = new Dictionary<UIElement, int>();
        private IEnumerable<UIElement> it = null;
        private int count;

        public void Execute(object target, params object[] parameters)
        {
            if (!(target is DesignerCanvas))
            {
                throw new InvalidCastException("The target must be a DesignerCanvas");
            }
            this.designerCanvas = (DesignerCanvas)target;

            if (parameters[0] is string)
            {
                this.movementType = (MovementType)new EnumConverter(typeof(MovementType)).ConvertFrom(parameters[0]);
            }
            else if (parameters[0] is MovementType)
            {
                this.movementType = (MovementType)parameters[0];
            }
            else
            {
                throw new InvalidCastException("The target must be a MovementType");
            }

            Redo();
        }

        public void Redo()
        {
            if (this.ordered.Count == 0)
            {
                if (this.movementType == MovementType.Forward)
                {
                    ordered = (from item in this.designerCanvas.SelectionService.CurrentSelection
                               orderby Canvas.GetZIndex(item as UIElement) descending
                               select item as UIElement).ToList();
                }
                else
                {
                    ordered = (from item in this.designerCanvas.SelectionService.CurrentSelection
                               orderby Canvas.GetZIndex(item as UIElement) ascending
                               select item as UIElement).ToList();
                }
                count = this.designerCanvas.Children.Count;
            }

            for (int i = 0; i < ordered.Count; i++)
            {
                int currentIndex = Canvas.GetZIndex(ordered[i]);
                int newIndex = 0;
                if (this.movementType == MovementType.Forward)
                    newIndex = Math.Min(count - 1 - i, currentIndex + 1);
                else
                    newIndex = Math.Max(i, currentIndex - 1);
                if (currentIndex != newIndex)
                {
                    if (this.elementsChanged.Count == 0)
                    {
                        elementsChanged.Add(ordered[i], currentIndex);
                    }
                    Canvas.SetZIndex(ordered[i], newIndex);
                    if (it == null)
                    {
                        it = this.designerCanvas.Children.OfType<UIElement>().Where(item => Canvas.GetZIndex(item) == newIndex);
                    }
                    foreach (UIElement elm in it)
                    {
                        if (elm != ordered[i])
                        {
                            if (!this.elementsChanged.ContainsKey(elm))
                            {
                                this.elementsChanged.Add(elm, Canvas.GetZIndex(elm));
                            }
                            else
                            {
                                this.elementsChanged[elm] = Canvas.GetZIndex(elm);
                            }
                            Canvas.SetZIndex(elm, currentIndex);
                            break;
                        }
                    }
                }
            }
        }

        public void Undo()
        {
            foreach (UIElement item in this.elementsChanged.Keys)
            {
                Canvas.SetZIndex(item, this.elementsChanged[item]);
            }
        }
    }

    public enum MovementType
    {
        Backward,
        Forward
    }
}
